sync: master → develop 2026-06-08 — backfill release #521 fixes#523
Conversation
…f path (#513 review) PR #513 chatgpt-codex review (P2) caught a real gap that PR #509 introduced when it added the `maxKeys` cap to `userDevicesCache`: - PR #509 added `safeCacheSet` handling to the cache-population path in `messages-send.ts:528-548` (where USync fills the cache). - The OTHER call-site that writes to `userDevicesCache` — `messages-recv.ts:2240` in the device-notification handler ('add' / 'remove' tags) — was left unprotected. `@cacheable/node-cache`'s capacity check is `keyCount() + 1 > maxKeys` — applied BEFORE the engine checks whether the key already exists. So once the cache reaches its `maxKeys` ceiling (5,000 entries), even an UPDATE to an already-cached user throws ECACHEFULL. The guard `if (!existingCache.length) continue` at line 2210 doesn't help: it only short-circuits when the user is NOT cached. A device-list update for an already-cached user would still hit the `.set` and throw. Real impact under sustained gateway load: - Cache hits 5,000 entries (a few dozen active groups will get there). - A device-add/remove notification arrives for one of the cached users. - `userDevicesCache.set(...)` throws ECACHEFULL. - The throw propagates into the message-receive handler and lands in Baileys' outer error boundary — connection survives, but a log-level error is emitted and the affected user's device list is NOT updated in the cache. - Next message-send for that user fetches the fresh list via USync (`getUSyncDevices`), which IS guarded — so the durable behavior eventually recovers. The fix routes the device-notif write through the same `safeCacheSet` helper PR #509 used in messages-send.ts. Same swallow-ECACHEFULL semantics, same debug log, same `getUSyncDevices` fallback path. Symmetric handling across the two call-sites that update the cache. Test plan: - npm run build ✓ (3 phases pass, zero errors) - 1 line of production change in `messages-recv.ts:2240`, plus comment explaining the WHY. No test changes needed — `safeCacheSet`'s behavior is already covered by `cache-utils.test.ts`. Out of scope (intentionally NOT touched): - Carousel, lists, buttons, polls, view-once, biz quality_control, useLegacyLock, TC token custom flow, LID↔PN batched, Phase 9 multi-DB, lidDbMigrated:false, the cacheMetricsInterval memory-leak fix, schema migrations + statement cache + busy retry. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Merges 6 PRs landed on `develop` since the previous master sync (2026-06-06), preserves the two auto-bumps that have since landed on master (#516, #517), and ships them together. PRs included in this release ============================ * #514 — chore(build): exclude .md from src→lib mirror Internal architecture notes (`src/Utils/multi-db-sqlite/ARCHITECTURE.md`, `USAGE.md`) no longer ship in the published package. Disk savings on consumer side + stops leaking internal phase planning into anyone that runs `npm install`. * #515 — chore(logs): compact recoverable Signal Protocol failures Recoverable Signal failures (Bad MAC, MessageCounterError, old counter, Invalid PreKey ID) are now compact one-liners at `warn` instead of three multi-KB `error` entries each. Per-event log output: ~10KB → ~250B. Unknown errors keep full stack + stanza. Net: error-dashboard noise drops dramatically without losing real signal. * #518 — feat(meta-ai): decrypt msmsg via empirically-validated WA Web Meta AI / FBID-bot replies (`<enc type="msmsg">`) now decrypt instead of NACKing with MissingMessageSecret. Algorithm reverse-engineered from `WAWebBotMessageSecret` via CDP and validated LIVE with a Meta AI "oi" capture. Five distinct bugs in upstream PR WhiskeySockets#2592 fixed (unbounded cache, cross-tenant leak, no FBID dispatch, drops streaming chunks, raw-id cache key, 12-strat brute force). Per-socket bounded LRU + `flushAll() + close()` on socket end to release the NodeCache timer. * #519 — feat(stickers): support lottieStickerMessage for animated .was Wraps + unwraps Lottie stickers (`application/was`) in `lottieStickerMessage` (FutureProofMessage at proto field 74), matching `WAWebE2EProtoGenerator`'s actual implementation. Mobile clients silently drop Lottie stickers in the unwrapped form; this makes them render on Android/iOS. Send-path `getMediaType` + DSM `messageContextInfo` reads both walk the wrap correctly. * #520 — fix(decode): preserve outer messageContextInfo when unwrapping deviceSentMessage Closes the codex P1 gap left deferred from #518. When WhatsApp delivers a fromMe-via-linked-device message, the OUTER `Message` carries `messageContextInfo.messageSecret` and the inner does not — the previous `msg = msg.deviceSentMessage?.message || msg` dropped that secret entirely. New `unwrapDeviceSentMessage` does a per-field merge matching WA Web's `l(e)` source exactly, including a length-check guard on `threadId` (protobuf decodes empty `repeated` as `[]` not `undefined` — naive `??` would lose the outer thread context). * #513 follow-up (already on master as `373a6f3622` from previous release) — the develop-side commit `50f9a77ef8` is the same change. Merge collapses both onto the master line; no behaviour change. Preserved from master (NOT touched by this merge) ================================================== * #516 — chore: update proto/version to v2.3000.1040989513 Auto-bumped `WAProto/WAProto.proto` + `baileys-version.json`. develop never touched these files, so the bump survives intact. * #517 — chore: update WhatsApp Web version to v2.3000.1040994085 Auto-bumped `baileys-version.json` again. Same — develop didn't touch it, master's value (`{"version":[2,3000,1040994085]}`) is preserved verbatim post-merge. Validation ========== * Auto-merge succeeded with ZERO conflicts — `messages-recv.ts` was the only file modified on both sides, but the edits were non-overlapping and git resolved them automatically. * `npm run build` clean on the merged tree. * 57/57 tests pass across the new-PR suites (dsm-context-info + meta-ai-msmsg + lottie-sticker-message + error-log-utils + process-message.protocol-guard). * `baileys-version.json` post-merge: `{"version":[2,3000,1040994085]}` — confirms master's auto-bump was preserved (NOT downgraded to develop's stale `1040973525`). Customizations preserved (NOT touched) ====================================== Carrossel, lists, buttons, polls, view-once, biz `quality_control`, `useLegacyLock`, TC token custom flow, LID↔PN batched, Phase 9 multi-DB, `lidDbMigrated:false`, `cacheMetricsInterval` memory-leak fix, schema migrations + statement cache + busy retry. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
5 findings from the release PR #521 audit applied before promoting develop → master. The release branch itself doesn't change; this PR lands the fixes on develop and the release branch will be refreshed to include them. P2 — Thread 1 (chatgpt) — reporting-token check reads outer wrap ================================================================ `messages-send.ts:1884` gated reporting-token attachment on `reportingMessage?.messageContextInfo?.messageSecret`. For Lottie stickers post-PR #519 that secret lives INSIDE the `lottieStickerMessage` wrap — the top-level read returns undefined and the token is silently skipped. Regression vs plain sticker behaviour. Fix: lift `messageContextInfo` from both locations the same way the initial-fanout DSM read does (the lift PR #519 already shipped on line ~1198): const reportingMessageSecret = reportingMessage?.lottieStickerMessage?.message ?.messageContextInfo?.messageSecret ?? reportingMessage?.messageContextInfo?.messageSecret Required adding `reportingMessage &&` to the surrounding `if` so TypeScript doesn't lose the narrowing it previously got from the inline property chain (the narrowing was the side-effect of reading `reportingMessage.messageContextInfo` in the condition itself). P2 — Thread 5 (coderabbit Major) — retry-resend DSM drops messageContextInfo ============================================================================ `messages-send.ts:1580` rebuilds the `deviceSentMessage` envelope on the retry-resend path WITHOUT carrying `messageContextInfo` along. The initial-fanout path got the lift in PR #519 (line ~1198); the retry path was missed. Concrete impact: when a companion device receives the RETRY of a Lottie sticker via DSM, our own `unwrapDeviceSentMessage` finds: - inner = messageToSend = { lottieStickerMessage: { message: { stickerMessage, messageContextInfo } } } - inner.messageContextInfo = undefined (it's nested in the wrap) - outer.messageContextInfo = undefined (the retry envelope omitted it) → messageSecret = undefined, reporting token / encrypted-edit decryption material lost on the companion's copy. Fix: same lift inline at the retry envelope build site. P2 — Thread 2 (chatgpt) — OrphanMsmsgError stub goes to Signal retry path ========================================================================= When `decryptMsmsgBotMessage` raises `OrphanMsmsgError` (cache miss), the catch in `decode-wa-message.ts` sets `messageStubType = CIPHERTEXT` and `messageStubParameters[0] = String(err.message)`. The receive handler at `messages-recv.ts:3115` checks for known stub-param strings and falls through to the Signal retry / PDO placeholder-resend path when none match — burning retry budget asking the bot for prekeys it has no business issuing, for a problem (missing CACHE entry) that a Signal retry can never fix. Fix: add a guard for `messageStubParameters[0]?.startsWith('decryptMsmsgBotMessage:')` right after the `MISSING_KEYS_ERROR_TEXT` branch. Plain ACK (no NACK, no retry) so the server considers the message delivered. The next bot reply that arrives after the outgoing-secret cache populates will decrypt cleanly. NOT a NACK MissingMessageSecret: that would tell the server to retransmit, and the retransmission will hit the same orphan state until the outgoing-side cache is populated (deferred per PR #518). P3 — Thread 4 (copilot) — `__internal` export not consumed ========================================================== `src/Utils/meta-ai-msmsg.ts` exported an `__internal` bag of helpers (`BOT_MESSAGE_INFO`, `KEY_LENGTH`, `isMeJid`, `deriveKeyAndDecrypt`, `decodeDecryptedMsmsg`, `userOnlyJid`, `isJidGroup`) that no file in the repo actually imports. Grep confirms zero call sites. Removed — the helpers stay module-private as intended. P3 — Thread 3 (copilot) — `(err as any)?.message` in auth-utils =============================================================== `src/Utils/auth-utils.ts:714` (the trace I added in PR #515 to log `transactWith rolled back` without duplicating the stack) used a plain `(err as any)?.message` cast. Tightened to `err instanceof Error ? err.message : String(err)` — no runtime change, just removes the `any` cast and gives string fallback for non-Error throws. Validation ========== * `npm run build` clean (TS narrowing fixed via explicit `reportingMessage &&` guard). * 57/57 tests pass across the new-PR suites (dsm-context-info-preservation + meta-ai-msmsg + lottie-sticker-message + error-log-utils + process-message.protocol-guard). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two findings from the cubic re-review on PR #521 that the previous audit-fix commit (cherry-picked from closed PR #522) didn't cover. Issue D (P2) — test re-implemented production helper ==================================================== cubic thread 8: `dsm-context-info-preservation.test.ts` kept a local copy of `unwrapDeviceSentMessage` and asserted against it. Comment claimed "if rules change in decode-wa-message.ts these break first" but that was wrong — the assertions tested the LOCAL copy, not production. Reverting `decode-wa-message.ts` to the old `msg = msg.deviceSentMessage?.message || msg` would leave all 10 tests green. The tests were validating themselves. Fix: * `decode-wa-message.ts` — flipped the helper from module-private `const` to `export const unwrapDeviceSentMessage`. The function is a leaf utility; exporting it surfaces nothing operational beyond what tests need. * `dsm-context-info-preservation.test.ts` — deleted the re-derived copy, imported from `../../Utils/decode-wa-message`. Header comment updated to explain WHY we now import (production parity) instead of re-derive. Issue E (P3) — `if (!err)` too broad in compactError ==================================================== cubic thread 9: `error-log-utils.ts:33` short-circuited every falsy input (including `0`, `''`, `false`, `NaN`) to the literal string `'Unknown'`. Those are unusual but valid thrown values — code that does `throw 0` would get its actual value erased. Operational impact near zero (Signal Protocol throws `Error` instances), but the contract is wrong. Fix: * `error-log-utils.ts` — `if (!err)` → `if (err == null)`. Comment added explaining the nullish-only narrowing. * `error-log-utils.test.ts` — new test `preserves falsy primitives that are NOT null/undefined` pins the new contract: `compactError(0)` → `'0'`, `compactError(false)` → `'false'`, etc. Validation ========== * `npm run build` clean * 58/58 tests pass (5 suites: dsm-context-info + error-log-utils + meta-ai-msmsg + lottie-sticker-message + process-message). Was 57; +1 from the new falsy-primitives test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI lint failed on the previous commit:
- error-log-utils.ts:36 — `if (err == null)` violated the codebase's
`eqeqeq` rule even though `== null` is the idiomatic nullish check.
Expanded to `if (err === null || err === undefined)` for the same
semantics with strict-equality compliance.
- meta-ai-msmsg.ts:46 — `isJidGroup` was imported but its only
consumer (the now-removed `__internal` export bag from cubic
audit thread 4) is gone. Removed from the import list.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
cubic re-review (thread 13, confidence 9) caught that the previous
ACK guard was too broad:
if (msg?.messageStubParameters?.[0]?.startsWith('decryptMsmsgBotMessage:'))
`decryptMsmsgBotMessage` throws with a `decryptMsmsgBotMessage:` prefix
for several distinct conditions, not just `OrphanMsmsgError`:
- `'decryptMsmsgBotMessage: no messageSecret for ${cacheKey}'`
← OrphanMsmsgError — cache miss, ACK + wait for cache to populate
- `'decryptMsmsgBotMessage: missing meta.target_id'`
← malformed stanza — deserves NACK/retry
- `'decryptMsmsgBotMessage: MessageSecretMessage missing encIv/encPayload'`
← malformed proto — deserves NACK/retry
- real AES-GCM auth-tag mismatch (string varies but may also start
with `decryptMsmsgBotMessage:` if wrapped)
← deserves the Signal retry path
The broader prefix silently ACK'd all of those, hiding real protocol
failures from the server-side retry machinery. Narrow the match to
the exact substring that uniquely identifies the orphan-cache case:
startsWith('decryptMsmsgBotMessage: no messageSecret for ')
Other `decryptMsmsgBotMessage:` failures now flow normally to the
Signal retry / PDO placeholder-resend path (where they belong).
Comment expanded to document why the narrow match is required.
Validation:
* build clean
* 58/58 tests still pass
Thread 12 (P3) — `String(err)` in auth-utils.ts:714 — is cosmetic
and deferred per the audit recommendation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
release: develop → master 2026-06-08 (5 PRs)
Brings develop in line with master after release PR #521 merged. master had two streams of commits develop didn't: 1. The release itself (PR #521, commit `285db5914b`) which merged develop's 5 PRs (#514, #515, #518, #519, #520) into master. 2. The 4 audit-fix commits applied DIRECTLY to the release branch (per the user's preference to keep release-time fixes inside the release PR rather than open a separate develop PR): - 7f5d723: 3 P2 + 2 P3 (reporting token, retry-resend DSM, orphan msmsg ACK, __internal cleanup, err typing) - 4214847: cubic threads 8+9 (export unwrapDeviceSentMessage + import in test, compactError nullish-only check) - b2c5abf: ESLint fixes (eqeqeq, unused isJidGroup import) - 2ec8ba3: cubic thread 13 (narrow `decryptMsmsgBotMessage:` match to `'no messageSecret for '` only) 3. The two auto-bumps that landed on master in the meantime: - 44b7c91: chore #516 proto/version v2.3000.1040989513 - b5d1bab: chore #517 WA Web version v2.3000.1040994085 Auto-merge succeeded with ZERO conflicts. Validation: * `npm run build` clean * 58/58 tests pass across all suites * `baileys-version.json` preserves master's auto-bumped value `{"version":[2,3000,1040994085]}` (not the stale develop value). * Thread 13 narrow guard present in messages-recv.ts (2 occurrences: 1 in comment, 1 in the actual `startsWith` check). After this lands, develop === master in terms of source content. Next feature/fix PRs branch off develop as usual. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Comment |
|
Thanks for opening this pull request and contributing to the project! The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch. In the meantime, anyone in the community is encouraged to test this pull request and provide feedback. ✅ How to confirm it worksIf you’ve tested this PR, please comment below with: This helps us speed up the review and merge process. 📦 To test this PR locally:If you encounter any issues or have feedback, feel free to comment as well. |
There was a problem hiding this comment.
💡 Codex Review
InfiniteAPI/src/Socket/messages-send.ts
Line 1917 in 20585f9
For Lottie stickers where the messageSecret only exists under lottieStickerMessage.message.messageContextInfo, this guard now enters the reporting-token path, but the call still passes the original reportingMessage to getMessageReportingToken. That helper reads only message.messageContextInfo?.messageSecret in src/Utils/reporting-utils.ts, so it returns null and the reporting token is still never attached for the exact wrapped-sticker case this change is trying to cover. Please either pass a reporting message with the secret lifted to top-level or teach the helper to read the nested Lottie context before generating the token.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
1 issue found across 10 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
Pull request overview
Syncs develop with master after release PR #521, backfilling the audit/lint fixes and preserving the upstream WhatsApp proto + web version bumps so the branches are source-identical again.
Changes:
- Preserves the proto/client version bumps (
WAProto.protoheader +baileys-version.json). - Backfills audit fixes around DSM context-info handling (incl. retry-resend) and msmsg orphan ACK behavior.
- Tightens error/logging utilities (
compactErrornullish-only) and aligns tests to the production helpers.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| WAProto/WAProto.proto | Updates the WhatsApp version header comment to the bumped proto version. |
| src/Utils/meta-ai-msmsg.ts | Removes unused import and drops the __internal test re-export. |
| src/Utils/error-log-utils.ts | Narrows compactError’s “Unknown” case to null/undefined only. |
| src/Utils/decode-wa-message.ts | Exports unwrapDeviceSentMessage for direct test coverage. |
| src/Utils/auth-utils.ts | Makes rollback trace logging robust for non-Error thrown values. |
| src/Socket/messages-send.ts | Lifts DSM messageContextInfo for retry-resend and adjusts reporting-token gating for wrapped Lottie messages. |
| src/Socket/messages-recv.ts | Narrows orphan-msmsg ACK guard to only the specific “no messageSecret for …” failure. |
| src/Defaults/baileys-version.json | Updates the WhatsApp Web version tuple to the latest bumped value. |
| src/tests/Utils/error-log-utils.test.ts | Adds regression coverage for falsy primitives in compactError. |
| src/tests/Utils/dsm-context-info-preservation.test.ts | Switches to importing the real unwrapDeviceSentMessage implementation for regression coverage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: rsalcara <rsalcara@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Summary
Brings
developin line withmasterafter release PR #521 landed. Strategy mirror: same approach used for previous master→develop syncs.What was on master but NOT develop
285db5914b2ec8ba3ccb'no messageSecret for 'b2c5abfaf64214847556unwrapDeviceSentMessage,compactErrornullish-only7f5d7231aa__internalremove, err typing44b7c9113ab5d1babf20The release-PR-time audit fixes were applied directly on the release branch (per the user's preference, not via separate develop PRs) — this sync brings them down to develop for parity.
Validation
npm run buildclean on the merged treebaileys-version.jsonpost-merge:{"version":[2,3000,1040994085]}— master's auto-bump preserved (NOT downgraded to develop's stale value)messages-recv.ts(verified by grep)After this lands,
develop === mastersource-wise. Next feature/fix PRs branch off develop as usual.🤖 Generated with Claude Code
Summary by cubic
Syncs develop with master after release #521. Backfills the msmsg ACK guard and DSM/Lottie context fixes, and preserves the latest proto and WA Web version bumps.
Bug Fixes
messageContextInfofor Lottie stickers and reads the reporting token from the wrapped context.unwrapDeviceSentMessagefor tests;compactErrornow treats only null/undefined as "Unknown"; safer error logging; removed unused internal export.Dependencies
baileys-version.jsonv2.3000.1041103517.Written for commit 296cfc8. Summary will update on new commits.